#include <jni.h>
#include <string>
#include <arm_neon.h>
#include <android/log.h>

#define LOG_TAG "JNI"
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)

void testAdd();
void swap_uv_neon(uint8_t *nv21_data, size_t stride);
void swapBytesTest();
void swapBytesTest2();
void swapBytesTest3();
void swapUVTest();

extern "C" JNIEXPORT jstring Java_cn_android666_neon_1simd_MainActivity_stringFromJNI(JNIEnv* env, jobject /* this */) {
    std::string hello = "Hello from C++!!!2222";
    LOGI("string = %s", hello.c_str());
//    testAdd();
//    swapBytesTest3();
    swapUVTest();
    return env->NewStringUTF(hello.c_str());
}

void testAdd() {
    LOGD("testAdd");
    // 定义a、b、c三个数组，等同于java中的 byte[8]
    unsigned char a[8] = {0, 1, 2, 3, 4, 5, 6, 7};
    unsigned char b[8] = {8, 9, 10, 11, 12, 13, 14, 15};
    unsigned char c[8];

    uint8x8_t regA, regB, regC; // 定义三个8x8bit的无符号整型的NEON寄存器，用于存放3个char数组。

    regA = vld1_u8(a); // 将a数组加载到regA寄存器中
    regB = vld1_u8(b); // 将b数组加载到regB寄存器中
    regC = vadd_u8(regA, regB); // 将regA和regB相加，并将结果保存到regC寄存器中
    vst1_u8(c, regC); // 将regC寄存器中的数据保存到c数组中

    for (int i = 0; i < 8; ++i) {
        LOGI("%d ", c[i]);
    }

}

// 交换一行的UV分量
void swap_uv_neon(uint8_t *nv21_data, size_t stride) {
    size_t remaining = stride;

    while (remaining >= 8) { // 处理16字节的块
        uint8x8_t data = vld1_u8(nv21_data); // 加载16个字节

        // 使用vrev16_u8交换UV
        uint8x8_t swapped_data = vrev16_u8(data);

        // 存储结果
        vst1_u8(nv21_data, swapped_data);

        nv21_data += 8;
        remaining -= 8;
    }

    // 剩余不足16字节的部分逐字节处理
    while (remaining--) {
        uint8_t temp = nv21_data[0];
        nv21_data[0] = nv21_data[1];
        nv21_data[1] = temp;

        nv21_data += 2;
    }
}


void swapBytes(uint8_t* data) {
    uint8x8_t bytes = vld1_u8(data);
    vrev64_u8(bytes);
    vst1_u8(data, bytes);
}

// Example usage:
void swapBytesTest() {
    uint8_t data[8] = {0, 1, 2, 3, 4, 5, 6, 7};

    uint8x8_t bytes = vld1_u8(data);
    uint8x8_t result = vrev16_u8(bytes);
    vst1_u8(data, result);

    for (int i = 0; i < 8; i++) {
        LOGI("%d ", data[i]);
    }
}

void swapBytesTest2() {
    uint8_t data[16] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15};

    uint8x16_t bytes = vld1q_u8(data);
    uint8x16_t result = vrev32q_u8(bytes);
    vst1q_u8(data, result);

    for (int i = 0; i < 16; i++) {
        LOGI("%d ", data[i]);
    }
}

/** 交换UV最快方式，一次交换16个字节中的UV */
void swapBytesTest3() {
    uint8_t data[16] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15};

    uint8x16_t bytes = vld1q_u8(data);
    uint8x16_t result = vrev16q_u8(bytes);
    vst1q_u8(data, result);

    for (int i = 0; i < 16; i++) {
        LOGI("%d ", data[i]);
    }
}

void swapUV(uint8_t *uvBytes, int length) {
    int remaining = length;

    while (remaining >= 16) { // 处理16字节的块
        uint8x16_t dataV = vld1q_u8(uvBytes);    // 加载16个字节
        uint8x16_t resultV = vrev16q_u8(dataV); // 交换UV
        vst1q_u8(uvBytes, resultV);              // 存储结果

        // 定位到下一个数据块继续处理
        uvBytes += 16;
        remaining -= 16;
    }

    // 剩余不足16字节的部分逐字节处理
    while (remaining > 0) {
        uint8_t temp = uvBytes[0];
        uvBytes[0] = uvBytes[1];
        uvBytes[1] = temp;

        uvBytes += 2;
        remaining -= 2;
    }
}

void swapUVTest() {
    uint8_t uvBytes[40] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39};
    swapUV(uvBytes, 40);
    for (int i = 0; i < 40; i += 2) {
        LOGI("%d %d", uvBytes[i], uvBytes[i + 1]);
    }
}